#include "main.h"
#include "oled.h"
#include "oled_data.h"

u8 OLED_GRAM[OLED_horizon][OLED_vertical/OLED_datasize] = {0};

//反显函数
void OLED_ColorTurn(u8 i)
{
	if(i==0)
	{
		OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
	}
	if(i==1)
	{
		OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
	}
}

//屏幕旋转180度
void OLED_DisplayTurn(u8 i)
{
	if(i==0)
	{
		OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
		OLED_WR_Byte(0xA1,OLED_CMD);
	}
	if(i==1)
	{
		OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
		OLED_WR_Byte(0xA0,OLED_CMD);
	}
}

void OLED_Set_Pos(unsigned char x, unsigned char y) 
{
	OLED_WR_Byte(0xb0 + y, OLED_CMD);
	OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
	OLED_WR_Byte((x & 0x0f) | 0x01, OLED_CMD);
}  

//开启OLED显示 
void OLED_DisPlay_On(void)
{
	OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
	OLED_WR_Byte(0x14,OLED_CMD);//开启电荷泵
	OLED_WR_Byte(0xAF,OLED_CMD);//点亮屏幕
}

//关闭OLED显示 
void OLED_DisPlay_Off(void)
{
	OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵使能
	OLED_WR_Byte(0x10,OLED_CMD);//关闭电荷泵
	OLED_WR_Byte(0xAE,OLED_CMD);//关闭屏幕
}

//更新显存到OLED	
void OLED_Refresh(void)
{
	u8 i,n;
	for(i=0;i<OLED_vertical/OLED_datasize;i++)
	{
		// OLED_WR_Byte(0xb0 + i,OLED_CMD); //设置行起始地址
		// OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
		// OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址
		I2C_TargetAddressConfig(I2C_OLED, I2C_OLED_ADDRESS, I2C_MASTER_WRITE);
		while (!I2C_CheckStatus(I2C_OLED, I2C_MASTER_TX_EMPTY));
		I2C_SendData(I2C_OLED, 0x00);//command
		while (!I2C_CheckStatus(I2C_OLED, I2C_MASTER_TX_EMPTY));
		I2C_SendData(I2C_OLED, 0xb0 + i);
		while (!I2C_CheckStatus(I2C_OLED, I2C_MASTER_TX_EMPTY));
		I2C_SendData(I2C_OLED, 0x00);
		while (!I2C_CheckStatus(I2C_OLED, I2C_MASTER_TX_EMPTY));
		I2C_SendData(I2C_OLED, 0x10);
		I2C_GenerateSTOP(I2C_OLED);
		while (I2C_ReadRegister(I2C_OLED, I2C_REGISTER_SR)&0x80000);

		I2C_TargetAddressConfig(I2C_OLED, I2C_OLED_ADDRESS, I2C_MASTER_WRITE);
		while (!I2C_CheckStatus(I2C_OLED, I2C_MASTER_TX_EMPTY));
		I2C_SendData(I2C_OLED, 0x40);//data	
		for(n=0;n<OLED_horizon;n++)
		{
			while (!I2C_CheckStatus(I2C_OLED, I2C_MASTER_TX_EMPTY));
			I2C_SendData(I2C_OLED, OLED_GRAM[n][i]);
		}
		I2C_GenerateSTOP(I2C_OLED);
		while (I2C_ReadRegister(I2C_OLED, I2C_REGISTER_SR)&0x80000);
  	}
}

//更新显存到OLED	
// void OLED_Refresh(void)
// {
// 	u8 i,n;
// 	for(i=0;i<OLED_vertical/OLED_datasize;i++)
// 	{
// 		OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
// 		OLED_WR_Byte(0x00,OLED_CMD);   //设置低列起始地址
// 		OLED_WR_Byte(0x10,OLED_CMD);   //设置高列起始地址
// 		I2C_Start();
// 		Send_Byte(0x78);
// 		I2C_WaitAck();
// 		Send_Byte(0x40);
// 		I2C_WaitAck();
// 		for(n=0;n<OLED_horizon;n++)
// 		{
// 			Send_Byte(OLED_GRAM[n][i]);
// 			I2C_WaitAck();
// 		}
// 		I2C_Stop();
// 	}
// }

void OLED_Clear(void)  
{
	// u8 i, n;
	memset(OLED_GRAM,0x00,sizeof(OLED_GRAM));
	// for (i = 0; i < 8; i++)
	// {
	// 	OLED_WR_Byte(0xb0 + i, OLED_CMD); // 设置页地址（0~7）
	// 	OLED_WR_Byte(0x00, OLED_CMD);	  // 设置显示位置—列低地址
	// 	OLED_WR_Byte(0x10, OLED_CMD);	  // 设置显示位置—列高地址
	// 	for (n = 0; n < 128; n++)
	// 		OLED_WR_Byte(0, OLED_DATA);
	// } // 更新显示
}
//画点 
//x:0~127
//y:0~63
//t:1 填充 0,清空	
void OLED_DrawPoint(u8 x,u8 y,u8 mode)
{
	u8 i, m, n;
	i = y / 8;
	m = y % 8;
	n = 1 << m;
	if(mode){OLED_GRAM[x][i]|=n;}
	else
	{
		OLED_GRAM[x][i]=~OLED_GRAM[x][i];
		OLED_GRAM[x][i]|=n;
		OLED_GRAM[x][i]=~OLED_GRAM[x][i];
	}
}

//画线
//x1,y1:起点坐标
//x2,y2:结束坐标
void OLED_DrawLine(u8 x1,u8 y1,u8 x2,u8 y2)
{
	u16 t;
	int xerr = 0, yerr = 0, delta_x, delta_y, distance;
	int incx, incy, uRow, uCol;
	delta_x = x2 - x1; // 计算坐标增量
	delta_y = y2 - y1;
	uRow = x1; // 画线起点坐标
	uCol = y1;
	if (delta_x > 0)
		incx = 1; // 设置单步方向
	else if (delta_x == 0)
		incx = 0; // 垂直线
	else
	{
		incx = -1;
		delta_x = -delta_x;
	}
	if (delta_y > 0)
		incy = 1;
	else if (delta_y == 0)
		incy = 0; // 水平线
	else
	{
		incy = -1;
		delta_y = -delta_x;
	}
	if (delta_x > delta_y)
		distance = delta_x; // 选取基本增量坐标轴
	else
		distance = delta_y;
	for (t = 0; t < distance + 1; t++)
	{
		OLED_DrawPoint(uRow, uCol,1); // 画点
		xerr += delta_x;
		yerr += delta_y;
		if (xerr > distance)
		{
			xerr -= distance;
			uRow += incx;
		}
		if (yerr > distance)
		{
			yerr -= distance;
			uCol += incy;
		}
	}
}
//x,y:圆心坐标
//r:圆的半径
void OLED_DrawCircle(u8 x,u8 y,u8 r)
{
	int a, b,num;
    a = 0;
    b = r;
    while(2 * b * b >= r * r)      
    {
        OLED_DrawPoint(x + a, y - b,1);
        OLED_DrawPoint(x - a, y - b,1);
        OLED_DrawPoint(x - a, y + b,1);
        OLED_DrawPoint(x + a, y + b,1);
 
        OLED_DrawPoint(x + b, y + a,1);
        OLED_DrawPoint(x + b, y - a,1);
        OLED_DrawPoint(x - b, y - a,1);
        OLED_DrawPoint(x - b, y + a,1);
        
        a++;
        num = (a * a + b * b) - r*r;//计算画的点离圆心的距离
        if(num > 0)
        {
            b--;
            a--;
        }
    }
}

//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//size1:选择字体 6x8/8x16
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
{
	u8 i, m, temp, size2, chr1;
	u8 x0 = x, y0 = y;

	if (size1 == 8)
		size2 = 6;
	else
		size2 = (size1 / 8 + ((size1 % 8) ? 1 : 0)) * (size1 / 2); // 得到字体一个字符对应点阵集所占的字节数
	chr1 = chr - ' ';											   // 计算偏移后的值

	for (i = 0; i < size2; i++)
	{
		if (size1 == 8)// 调用0806字体
		{
			temp = OLED_F6x8[chr1][i];//下到上，左到右
		} 
		else if (size1 == 16)// 调用1608字体
		{
			temp = OLED_F8x16[chr1][i];
		}
		else return;

		for (m = 0; m < 8; m++)
		{
			if (temp & 0x01)
				OLED_DrawPoint(x, y, 1);//上到下，左到右
			else
				OLED_DrawPoint(x, y, 0);
			temp >>= 1;
			y++;
		}
		x++;
		if ((size1 != 8) && ((x - x0) == size1 / 2))
		{
			x = x0;
			y0 = y0 + 8;
		}
		y = y0;
	}
}

//显示字符串
//x,y:起点坐标  
//size1:字体大小 
//*chr:字符串起始地址 
//mode:0,反色显示;1,正常显示
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 size1)
{
	while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
	{
		OLED_ShowChar(x, y, *chr, size1);
		if (size1 == 8)
			x += 6;
		else
			x += size1 / 2;
		chr++;
  }
}

//m^n
u32 OLED_Pow(u8 m,u8 n)
{
	u32 result=1;
	while(n--)
	{
	  result*=m;
	}
	return result;
}

//显示数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:0,反色显示;1,正常显示
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size1)
{
	u8 t, temp, m = 0;
	if (size1 == 8)
		m = 2;
	for (t = 0; t < len; t++)
	{
		temp = (num / OLED_Pow(10, len - t - 1)) % 10;
		if (temp == 0)
		{
			OLED_ShowChar(x + (size1 / 2 + m) * t, y, '0', size1);
		}
		else
		{
			OLED_ShowChar(x + (size1 / 2 + m) * t, y, temp + '0', size1);
		}
	}
}

//x,y：起点坐标
//sizex,sizey,图片长宽
//BMP[]：要写入的图片数组
//mode:0,反色显示;1,正常显示
void OLED_ShowPicture(u8 x,u8 y,u8 sizex,u8 sizey,u8 BMP[])
{
	u8 i, n, temp, m;
	u16 j = 0;
	u8 x0 = x, y0 = y;
	sizey = sizey / 8 + ((sizey % 8) ? 1 : 0);
	for (n = 0; n < sizey; n++)
	{
		for (i = 0; i < sizex; i++)
		{
			temp = BMP[j];
			j++;
			for (m = 0; m < 8; m++)
			{
				if (temp & 0x01)
					OLED_DrawPoint(x, y, 1);
				else
					OLED_DrawPoint(x, y, 0);
				temp >>= 1;
				y++;
			}
			x++;
			if ((x - x0) == sizex)
			{
				x = x0;
				y0 = y0 + 8;
			}
			y = y0;
		}
	}
}

void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{
	unsigned int j = 0;
	unsigned char x, y;

	if (y1 % 8 == 0)
		y = y1 / 8;
	else
		y = y1 / 8 + 1;
		
	for (y = y0; y < y1; y++)
	{
		OLED_Set_Pos(x0, y);
		for (x = x0; x < x1; x++)
		{
			OLED_WR_Byte(BMP[j++], OLED_DATA);
		}
	}
}

//OLED的初始化
void OLED_Init(void)
{					  
	OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
	OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
	OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
	OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
	OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
	OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/64 duty
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	OLED_WR_Byte(0x00,OLED_CMD);//-not offset
	OLED_WR_Byte(0xD5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
	OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
	OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
	OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
	OLED_WR_Byte(0x12,OLED_CMD);
	OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
	OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
	OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
	OLED_WR_Byte(0x02,OLED_CMD);//
	OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
	OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
	OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
	OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) 
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel

	OLED_DisPlay_Off();
	OLED_Clear();
	OLED_DisPlay_On();
}

void oled_test(void)
{
	OLED_ShowString(0,2*8,"this is oled line 3",8);
	OLED_ShowString(0,3*8,"this is oled line 4",8);
}
